import configparser, os

from typing import Optional
from passlib.context import CryptContext
from jose import JWTError, jwt
from datetime import datetime, timedelta
from fastapi import Depends
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.orm.session import Session

from .models import Users

from .database import SessionLocal
from .crud import users

config = configparser.ConfigParser()

path = os.path.join(os.getcwd(), 'mini-judge', 'sql_config.ini')

config.read(path)

SECRET_KEY = config['security']['secret_key']
ALGORITHM = config['security']['algorithm']
ACCESS_TOKEN_EXPIRE_MINUTES = int(config['security']['access_token_expire_minutes'])

pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto')
oauth2_scheme = OAuth2PasswordBearer(tokenUrl='sql/token')

# 获取数据库Session
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# 信息加密与校验
def hash_password(password: str):
    """返回哈希密码，相同密码返回的哈希密码不同"""
    return pwd_context.hash(password)

def verify_password(plain: str, hashed: str):
    """对明文与哈希密码进行验证"""
    return pwd_context.verify(plain, hashed)

# 认证用户
def authenticate_user(number: str, password: str, db: Session):
    user = users.get_user_by_number(db, user_number=number)
    return user if (user and verify_password(password, user.password)) else None

# token生成与校验
def create_access_token(data: dict, expires_delta: Optional[timedelta]=None):
    to_encode = data.copy()
    expire = datetime.utcnow() + (expires_delta if expires_delta else timedelta(minutes=15))
    to_encode.update({'exp': expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

def get_current_user(token: str=Depends(oauth2_scheme), db: Session=Depends(get_db)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        number: str = payload.get('sub')
        if not number:
            return None
    except JWTError:
        print(JWTError)
        return None
    return users.get_user_by_number(db, number)

def get_current_active_user(current_user: Users=Depends(get_current_user)):
    return current_user if current_user and current_user.enabled else None